home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / ExceptionHandler-C-src / GetZoneList (LightSpeed).c < prev    next >
Text File  |  1990-09-10  |  17KB  |  620 lines

  1. /* ------------------------------------------------------------------------------
  2. #    Modified for LightSpeed C by R. Mark Fleming Jan. 30, 1990
  3. #
  4. #    Apple Macintosh Developer Technical Support
  5. #
  6. #    AppleTalk GetZoneList Sample Application
  7. #
  8. #    GetZoneList
  9. #
  10. #    GetZoneList.c    -    C Source
  11. #
  12. #    Copyright © 1989 Apple Computer, Inc.
  13. #    All rights reserved.
  14. #
  15. #    Versions:    1.0                    11/88
  16. #                1.1                    10/89
  17. #
  18. #    Components:    GetZoneList.p        October 1, 1989
  19. #                GetZoneList.c        October 1, 1989
  20. #                GetZoneList.r        October 1, 1989
  21. #                PGetZoneList.make    October 1, 1989
  22. #                CGetZoneList.make    October 1, 1989
  23. #
  24. #    Requirements:
  25. #                UFailure.p            November 1, 1988
  26. #                UFailure.inc1.p        November 1, 1988
  27. #                UFailure.a            November 1, 1988
  28. #
  29. #    GetZoneList is a sample application that uses
  30. #    AppleTalk ATP and ZIP to obtain a list of zones
  31. #    on an AppleTalk internet.
  32. #
  33. #    GetZoneList also demonstrates using a signal, or
  34. #    failure-catching mechanism to recover from error
  35. #    situations.  Since C does not allow nested procedures
  36. #    a la Pascal, a few modifications were made to incorporate
  37. #    the failure handling and keep this sample fairly close in
  38. #    design to the Pascal sample.  
  39. #    (Gee, thanks a lot M2 for using nested procs. - pvh)
  40. #
  41. #    GetZoneList is based on MACDTS Sample.c. For more
  42. #    description and explanation of the non-example
  43. #    specific areas of this application, please refer to
  44. #    either Sample.p or TESample.c.
  45. #    PSendRequest() & GetBridgeAddress() - nAppleTalk library
  46. ------------------------------------------------------------------------------ */
  47. #include "MyExceptionHandler.h"
  48. #include "GetZoneInclude.h"
  49.  
  50. /* Globs */
  51. SysEnvRec    gMac;                    /* set up by Initialize */
  52. Boolean        gHasWaitNextEvent;        /* set up by Initialize */
  53. Boolean        gInBackground;            /* maintained by Initialize and DoEvent */
  54.     
  55. ListHandle    gList;                    /* the list to be filled with zone names */
  56.  
  57. /*     globals added for C sample use as the Pascal 
  58.     example used those horrid :-) nested procedures! */
  59. ATPPBPtr    gATPPBPtr;    /* the parameter block for GetZoneList call */
  60. Ptr            gZones;     /* the data buffer for GetZoneList call */
  61. DialogPtr    gErrDlg;    /* Dialog used for displaying zone list */ 
  62.  
  63. Boolean TrapAvailable(short, int);
  64.  
  65. void FailOSErrMsg(result, message)
  66.     short    result;
  67.     short    message;
  68. {
  69.     if (result != noErr)    Failure(result, message);
  70. } /* SignalOSErrMsg */
  71.  
  72.  
  73. void FailnilMsg(p, message)
  74.     Ptr        p;
  75.     short    message;
  76. {
  77.     if (p == nil)    Failure(memFullErr, message);
  78. } /* FailNILMsg */
  79.  
  80.  
  81. void AlertUser(error, message)
  82.  
  83. /* Display an alert to inform the user of an error. Message acts as an 
  84.  index into a STR# resource of error messages. if no message is given,
  85.  i.e. = 0, then use a standard message. if error is not noErr then
  86.  display it as well. */
  87.  
  88.     short    error;
  89.     long    message;
  90. {
  91.     Str255    msg1, msg2;
  92.     short    itemHit;
  93.  
  94.     if (message == 0L)  message = eStandardErr;
  95.     GetIndString(msg1, sErrStrings, message);
  96.     if (error == noErr) msg2[0] = '';
  97.     else NumToString(error, msg2);
  98.     ParamText(msg1, msg2, "\p", "\p");
  99.     itemHit = Alert(rUserAlert, nil);
  100. } /* AlertUser */
  101.  
  102.  
  103. Boolean IsDAWindow(window)
  104.     WindowPtr    window;
  105. {
  106.     if (window == nil) return (false);
  107.     else    /* DA windows have negative windowKinds */
  108.         return ((WindowPeek) window)->windowKind < 0;
  109. } /* IsDAWindow */
  110.  
  111.  
  112. Boolean IsAppWindow(window)
  113.     WindowPtr    window;
  114. {
  115.     short        windowKind;
  116.  
  117.     if ( window == nil ) return false;
  118.     else {    
  119.     /* application windows have 
  120.         windowKinds >= userKind (8) or dialogKind (2) */
  121.         windowKind = ((WindowPeek) window)->windowKind;
  122.         return (windowKind >= userKind) || (windowKind == dialogKind);
  123.     }
  124. } /* IsAppWindow */
  125.  
  126.  
  127. void ZoneListCleanUp()
  128. {
  129.     if (gATPPBPtr != nil)
  130.                         DisposPtr((Ptr)gATPPBPtr); /* get rid of pb block */
  131.     if (gZones != nil)    DisposPtr(gZones);        /* and buffer */
  132. } /* ZoneListCleanUp */
  133.  
  134.  
  135. pascal void HandleZoneListErr(error, message)
  136. short error;
  137. long message;
  138. {
  139.     ZoneListCleanUp();                        /* get rid of allocated junk */
  140. } /* HandleZoneListErr */
  141.  
  142.  
  143. void BuildZoneList()
  144.  
  145. /*     Create the list of zones on the network. Find a bridge to talk to , if one is
  146.      present, then ask it for zone names. Add the names to the list in the dialog.    */
  147.  
  148. {
  149.     BDSElement    dBDS;                /* the BDS for GetZoneList call */
  150.     Ptr            dCurr;                /* the data buffer for GetZoneList call */
  151.     short        dIndex, dCount;
  152.     short        ignore;
  153.     Cell        cSize;
  154.     
  155.     FailInfo    fi;
  156.  
  157.     gATPPBPtr = nil;                                            /* init some important variables*/
  158.     gZones = nil;
  159.  
  160.     CatchCFailures(&fi, HandleZoneListErr);
  161.     
  162.     gATPPBPtr = (ATPPBPtr)NewPtr(sizeof(ATPParamBlock));
  163.     FailnilMsg(gATPPBPtr, eNoMemory);
  164.     
  165.     gZones = NewPtr(kZonesSize);
  166.     FailnilMsg(gZones, eNoMemory);
  167.     
  168.     dBDS.buffSize = kZonesSize;                                    /* set up BDS */
  169.     dBDS.buffPtr = gZones;
  170.         
  171.     gATPPBPtr->ATPatpFlags = 0;
  172.         
  173.     FailOSErrMsg(GetNodeAddress(&ignore, &gATPPBPtr->ATPaddrBlock.aNet), eAppleTalk);    /* get net of bridge */
  174.         
  175.     if (gATPPBPtr->ATPaddrBlock.aNet == 0) Failure(0, eNoZones);    /* bail if no zones present */
  176.  
  177.     gATPPBPtr->ATPaddrBlock.aNode = GetBridgeAddress();            /* get node of bridge */
  178.     gATPPBPtr->ATPaddrBlock.aSocket = kZIPSocket;                /* the socket we want */
  179.     gATPPBPtr->ATPreqLength = 0;
  180.     gATPPBPtr->ATPreqPointer = nil;
  181.     gATPPBPtr->ATPbdsPointer = (Ptr) &dBDS;
  182.     gATPPBPtr->ATPnumOfBuffs = 1;
  183.     gATPPBPtr->ATPtimeOutVal = kATPTimeOutVal;
  184.     gATPPBPtr->ATPretryCount = kATPRetryCount;
  185.  
  186.     dIndex = 1;
  187.     dCount = 0;
  188.     SetPt(&cSize, 0, 0);                                                /* we always stuff into first */
  189.     
  190.     do {
  191.         gATPPBPtr->ATPuserData = kGZLCall + dIndex;                        /* indicate GetZoneList request */
  192.         FailOSErrMsg(PSendRequest(gATPPBPtr, false), eAppleTalk);        /* send sync request */
  193.         
  194.         dCount = dCount + dBDS.userBytes & kZoneCount;                    /* find out how many returned */
  195.         dCurr = gZones;                                                    /* put current pointer at start */
  196.         do {                                                            /* get each zone */
  197.             ignore = LAddRow(1, 0, gList);                                /* create new cell at start */
  198.             LSetCell((Ptr)dCurr + 1L, (short) *dCurr, cSize, gList);    /* stuff in zone */
  199.             dCurr = (Ptr)(dCurr + *dCurr + 1 );                            /* bump up current pointer */
  200.             dIndex = dIndex + 1;                                        /* increment which zone */
  201.         } while(! (dIndex > dCount));
  202.         
  203.     } while ((dBDS.userBytes & kMoreZones) == 0);                /*     keep going until none left */
  204.     
  205.     ZoneListCleanUp();
  206.     
  207.     Success(&fi);
  208. } /* BuildZoneList */
  209.  
  210.  
  211. pascal void ZoneListDraw(dlg, item)
  212.     DialogPtr    dlg;
  213.     short        item;
  214. {
  215.  
  216. /* The user item void for the zone list user item and default
  217.  box user item in the dialog. Draw the list and the frame that goes with it.
  218.  Draw the default box around the OK button */
  219.  
  220.     GrafPtr     port;
  221.     short        kind;
  222.     Handle        h;
  223.     Rect        r;
  224.     PenState    ps;
  225.  
  226.     GetPort(&port);                                        /* save old port */
  227.     SetPort(dlg);                                        /* make dialog port */
  228.  
  229.     switch (item) {
  230.         case dZoneList: 
  231.             LUpdate(dlg->visRgn, gList);                /* re-draw list */
  232.             GetDItem(dlg, dZoneList, &kind, &h, &r);
  233.             InsetRect(&r, kListInset, kListInset);
  234.             FrameRect(&r);                                /* re-draw frame */
  235.             break;
  236.             
  237.         case dDefault:
  238.             GetDItem(dlg, dDefault, &kind, &h, &r);
  239.             GetPenState(&ps);
  240.             PenSize(3, 3);
  241.             InsetRect(&r, -4, -4);
  242.             FrameRoundRect(&r, 16, 16);                    /* draw default box */
  243.             SetPenState(&ps);
  244.             break;
  245.         }
  246.     SetPort(port);                                        /* restore old port */
  247. } /* ZoneListDraw */
  248.  
  249.  
  250. pascal Boolean ListFilter (dlg, event, item)
  251.     DialogPtr    dlg;
  252.     EventRecord    *event;
  253.     short        *item;
  254. {
  255.  
  256. /*    Passed as parameter to ModalDialog. Handle key presses and mouse clicks
  257.        from the user. Do all the right default actions since we override them
  258.      by virtue of our existence.    */
  259.  
  260.     GrafPtr        port;
  261.     Point        loc;
  262.     short        kind;
  263.     Handle        h;
  264.     Rect        r;
  265.     Boolean        ignore;
  266.     char        key;
  267.     long         finalTicks;
  268.  
  269.     Boolean        returnValue;
  270.     
  271.     returnValue = false;                                    /*    always default false */
  272.  
  273.     switch (event->what) {
  274.         case keyDown:                                         /*    check for <cr> or <enter> */
  275.         case autoKey:
  276.             key = (char) event->message;
  277.             if (key == kCR || key == kENTER) {                /*    it was a <cr> or <enter> */
  278.                 GetDItem(dlg, ok, &kind, &h, &r);
  279.                 HiliteControl((ControlHandle)h, kHilite);
  280.                 Delay(kHiliteDelay, &finalTicks);
  281.                 HiliteControl((ControlHandle)h, kDeHilite);
  282.                 returnValue = true;                            /*    so we handle it */
  283.                 *item = 1;                                    /*    and make the first item hit */
  284.                 }
  285.             break;
  286.         case mouseDown:                                             /*    we want mouseDowns */
  287.             GetPort(&port);
  288.             SetPort(dlg);
  289.             loc = event->where;
  290.             GlobalToLocal(&loc);                                    /*    find where clicked */
  291.             GetDItem(dlg, dZoneList, &kind, &h, &r);                /*    get rect for list */
  292.             if (PtInRect(loc, &r)) {                                /*    if clicked inside… */
  293.                 returnValue = true;                                    /*    we take care of it */
  294.                 ignore = LClick(loc, event->modifiers, gList);        /*    by passing click to list */
  295.                 }
  296.             SetPort(port);
  297.             break;
  298.         }
  299.     return (returnValue);
  300. } /* ListFilter */
  301.  
  302.  
  303. void CleanUp_DoZoneList()
  304. {
  305.     if (gList != nil) LDispose(gList);            /*    get rid of list */
  306.     if (gErrDlg != nil) DisposDialog(gErrDlg);    /*    get rid of dialog */
  307. } /* CleanUp_DoZoneList */
  308.  
  309.  
  310. pascal void HandleErr_DoZoneList(error, message)
  311. short error; long message;
  312. {
  313.     CleanUp_DoZoneList();                                /*    release junk */
  314. } /* HandleErr_DoZoneList */
  315.  
  316.  
  317. void DoZoneList()
  318.  
  319. /*    Put up a modal dialog that shows a list of the zones on the net. Create the dialog
  320.  and list, call BuildZoneList to fill it, then wait for the user to click OK. */
  321.  
  322. {
  323.     DialogPtr    dlg;
  324.     short        item, kind;
  325.     Handle        h;
  326.     Rect        r, rView, dataBounds;
  327.     Cell        cSize;
  328.     FailInfo    fi;
  329.     short        hor, ver;
  330.     
  331.     gList = nil;                                            /*    init some important variables */
  332.     dlg = nil;
  333.  
  334.     CatchCFailures(&fi, HandleErr_DoZoneList);
  335.  
  336.     
  337.     dlg = GetNewDialog(rZoneDialog, nil, (WindowPtr)-1);            /*    create dialog */
  338.     
  339.     gErrDlg = dlg;
  340.     
  341.     FailnilMsg(dlg, eNoMemory);
  342.     
  343.     /*    We center the dialog horizontally and position it vertically one-third the
  344.      distance from the menu bar to the bottom of the main device. We do not
  345.      check for the dialog extending past the bottom of the device because we
  346.      know the dialog is not that big. You may wish to make that check. */
  347.         
  348.     hor = dlg->portRect.right - dlg->portRect.left;
  349.  
  350.     hor = ((screenBits.bounds.right - screenBits.bounds.left) - hor) / 2;
  351.     ver = ((screenBits.bounds.bottom - screenBits.bounds.top) - GetMBarHeight()) / 3;
  352.  
  353.     MoveWindow(dlg, hor, ver, false);
  354.     
  355.     GetDItem(dlg, dDefault, &kind, &h, &r);
  356.     SetDItem(dlg, dDefault, kind, (Handle) ZoneListDraw, &r);
  357.     GetDItem(dlg, dZoneList, &kind, &h, &r);
  358.     SetDItem(dlg, dZoneList, kind, (Handle) ZoneListDraw, &r);        /*    connect drawing void */
  359.     rView = r;
  360.     rView.right -= kScrollBarWidth;                            /*    adjust rectangle for scroll */
  361.     SetRect(&dataBounds, 0, 0, 1, 0);                        /*    init to one-wide list */
  362.     SetPt(&cSize, 0, 0);
  363.     gList = LNew(&rView, &dataBounds, cSize, 0, (WindowPtr)dlg,
  364.                     false, false, false, true);                /*    create with vertical scroll */
  365.     FailnilMsg(gList, eNoMemory);
  366.     BuildZoneList();                                        /*    put the stuff into the list */
  367.     SetPt(&cSize, 0, 0);
  368.     LSetSelect(true, cSize, gList);                            /*    select the first guy */
  369.     LDoDraw(true, gList);                                    /*    turn on the list */
  370.     ShowWindow(dlg);                                        /*    turn on the dialog */
  371.  
  372.     do {
  373.         ModalDialog((ModalFilterProcPtr) ListFilter, &item);    /*    accept events */
  374.         } while (item != ok);                                    /*    until he presses 'ok' */
  375.     
  376.     CleanUp_DoZoneList();
  377.     
  378.     Success(&fi);
  379. } /* DoZoneList */
  380.  
  381.  
  382. Boolean DoCloseWindow(window)
  383.     WindowPtr    window;
  384. {
  385.     Boolean     functionValue = true;
  386.     
  387.     if (IsDAWindow(window))
  388.         CloseDeskAcc((short) ((WindowPeek)window)->windowKind);
  389.     else
  390.     if (IsAppWindow(window)) CloseWindow(window);
  391.  
  392.     return(functionValue);
  393. } /* DoCloseWindow */
  394.  
  395. void Terminate()
  396. {
  397.     WindowPtr    aWindow;
  398.     Boolean        closed;
  399.  
  400.     closed = true;
  401.     do {
  402.         aWindow = FrontWindow();                /*    get the current front window */
  403.         if (aWindow != nil)
  404.             closed = DoCloseWindow(aWindow);    /*    close this window */
  405.     } while ((closed) && (aWindow != nil));        /*    do all windows */
  406.     if (closed)    ExitToShell();                    /*    exit if no cancellation */
  407. } /* Terminate */
  408.  
  409.  
  410. void AdjustMenus()
  411. {
  412.     WindowPtr    window;
  413.     MenuHandle    menu;
  414.  
  415.     window = FrontWindow();
  416.  
  417.     menu = GetMHandle(mFile);
  418.     if (IsDAWindow(window))                /*    we can allow desk accessories to be closed from the menu */
  419.         EnableItem(menu, iClose);
  420.     else
  421.         DisableItem(menu, iClose);        /*    but not our traffic light window */
  422.  
  423.     menu = GetMHandle(mEdit);
  424.     if (IsDAWindow(window)) {            /*    a desk accessory might need the edit menu */
  425.         EnableItem(menu, iUndo);
  426.         EnableItem(menu, iCut);
  427.         EnableItem(menu, iCopy);
  428.         EnableItem(menu, iPaste);
  429.         EnableItem(menu, iClear);
  430.     } else {                            /*    but we know we do not */
  431.         DisableItem(menu, iUndo);
  432.         DisableItem(menu, iCut);
  433.         DisableItem(menu, iCopy);
  434.         DisableItem(menu, iClear);
  435.         DisableItem(menu, iPaste);
  436.         }
  437. } /* AdjustMenus */
  438.  
  439.  
  440. pascal void HandleMenu(error, message)
  441. short error; long message;
  442. {
  443.     HiliteMenu(0);                                /*    unhighlight what MenuSelect (or MenuKey) hilited */
  444. } /* HandleMenu */
  445.  
  446.  
  447. void DoMenuCommand(menuResult)
  448.     long    menuResult;
  449. {
  450.     short        menuID;                            /*    the resource ID of the selected menu */
  451.     short        menuItem;                        /*    the item number of the selected menu */
  452.     short        itemHit;
  453.     Str255        daName;
  454.     short        daRefNum;
  455.     Boolean        handledByDA    ;
  456.     Boolean        ignore;
  457.     FailInfo    fi;
  458.  
  459.     CatchCFailures(&fi, (HandlerFuncPtr) HandleMenu);
  460.     
  461.     menuID = HiWord(menuResult);        /*    use built-ins (for efficiency)... */
  462.     menuItem = LoWord(menuResult);        /*    to get menu item number and menu number */
  463.     switch (menuID) {
  464.         case mApple:
  465.             switch (menuItem) {
  466.                 case iAbout:    /*    bring up alert for About */
  467.                     itemHit = Alert(rAboutAlert, nil);
  468.                     break;
  469.                 default:        /*    all non-About items in this menu are DAs */
  470.                     GetItem(GetMHandle(mApple), menuItem, daName);
  471.                     daRefNum = OpenDeskAcc(daName);
  472.                     break;
  473.                 }
  474.             break;
  475.         case mFile:
  476.             switch (menuItem) {
  477.                 case iNew:
  478.                     DoZoneList();
  479.                     break;
  480.                 case iClose:
  481.                     ignore = DoCloseWindow(FrontWindow());
  482.                     break;
  483.                 case iQuit:
  484.                     Terminate();
  485.                     break;
  486.                 }
  487.             break;
  488.         case mEdit:                                    /*    call SystemEdit for DA editing & Multifinder */
  489.             handledByDA = SystemEdit(menuItem-1);    /*    since we don't do any editing */
  490.             break;
  491.         }
  492.  
  493.     HiliteMenu(0);                                    /*    cleanup */
  494.  
  495.     Success(&fi);
  496. } /* DoMenuCommand */
  497.  
  498. void AdjustCursor(mouse, region)
  499. Point mouse; RgnHandle region;
  500. {
  501.  
  502. } /* AdjustCursor */
  503.  
  504.  
  505. pascal void HandleErr_DoEvent(error, message)
  506.     short    error;
  507.     long    message;
  508. {
  509.     if (error > 0)    AlertUser(0, error);
  510.     else            AlertUser(error, message);
  511.     ExitToShell();
  512. } /* HandleErr_DoEvent */
  513.  
  514.  
  515. void DoEvent(event)
  516.     EventRecord    event;
  517. {
  518.     short        part;
  519.     WindowPtr    window;
  520.     char        key;
  521.     FailInfo    fi;
  522.     Point        aPoint;
  523.     OSErr        err;
  524.     
  525.     CatchCFailures(&fi, (HandlerFuncPtr) HandleErr_DoEvent);
  526.     
  527.     switch (event.what) {
  528.         case mouseDown: 
  529.             part = FindWindow(event.where, &window);
  530.             switch (part) {
  531.                 case inMenuBar:                            /*    process the menu command */
  532.                     AdjustMenus();
  533.                     DoMenuCommand(MenuSelect(event.where));
  534.                     break;
  535.                 case inSysWindow:                        /*    let the system handle the mouseDown */
  536.                     SystemClick(&event, window);
  537.                     break;
  538.                 case inContent:
  539.                     break;
  540.                 case inDrag:
  541.                     break;
  542.                 case inGrow:
  543.                     break;
  544.                 case inZoomIn: 
  545.                 case inZoomOut:
  546.                     break;
  547.                 }
  548.             break;
  549.         case keyDown:                             /*    check for menukey equivalents */
  550.         case autoKey:
  551.             key = event.message & charCodeMask;
  552.             if (event.modifiers & cmdKey) {        /*    Command key down */
  553.                 if (event.what == keyDown) {
  554.                     AdjustMenus();                /*    enable/disable/check menu items properly */
  555.                     DoMenuCommand(MenuKey(key));
  556.                     }
  557.                 }
  558.             break;
  559.         /*    call DoActivate with the window and... */
  560.         case activateEvt:
  561.             break;
  562.         case updateEvt:
  563.             break;
  564.             
  565.         /* It is not a bad idea to at least call DIBadMount in response
  566.          to a diskEvt, so that the user can format a floppy. */
  567.         case diskEvt:
  568.             if (HiWord(event.message) != noErr) {
  569.                 SetPt(&aPoint, kDILeft, kDITop);
  570.                 err = DIBadMount(aPoint, event.message);
  571.             }
  572.         case kOSEvent:
  573.             switch ((event.message >> 24) & 0x0FF) {     /* high byte of message */
  574.                 case kSuspendResumeMessage:
  575.                     gInBackground = event.message & kResumeMask;
  576.                     break;
  577.                 }
  578.             break;
  579.         }    
  580.     Success(&fi);
  581. } /* DoEvent */
  582.  
  583.  
  584. void EventLoop()
  585. {
  586.     RgnHandle    cursorRgn;
  587.     Boolean        gotEvent;
  588.     EventRecord    event;
  589.     
  590.     cursorRgn = NewRgn();            /*    we’ll pass WNE an empty region the 1st time thru */
  591.  
  592.     do {
  593.         if (gHasWaitNextEvent)        /*    put us 'asleep' forever under Multifinder */
  594.             gotEvent = WaitNextEvent(everyEvent, &event, MAXLONG, cursorRgn);
  595.         else {
  596.             SystemTask();            /*    must be called if using GetNextEvent */
  597.             gotEvent = GetNextEvent(everyEvent, &event);
  598.             }
  599.             
  600.         if (gotEvent) {
  601.             AdjustCursor(event.where, cursorRgn); /*    make sure we have the right cursor */
  602.             DoEvent(event);
  603.             }
  604.         AdjustCursor(event.where, cursorRgn);
  605.     } while (true);        /*    loop forever; we quit through an ExitToShell */
  606. } /* EventLoop */
  607.  
  608.  
  609. void main()
  610. {    
  611.     MaxApplZone();                    /*    expand the heap so code segments load at the top */
  612.  
  613.     InitUFailure();    
  614.  
  615.     Initialize();                    /* initialize the program */
  616.     UnloadSeg(Initialize);            /* note that Initialize must not be in Main! */
  617.  
  618.     EventLoop();                    /* call the main event loop */
  619. } /* main */
  620.